package com.liustar.common.util;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 属性拾取器
 *
 * @Author:Leo
 * @Date:2017/9/5 9:32
 */
public class PropertyPicker {
    private final static Logger logger = LogManager.getLogger(PropertyPicker.class);

    /**
     * 对象到对象
     *
     * @param <T>
     * @param <E>
     * @param targetClass
     * @param source
     * @return
     */
    public static <T, E> T pick(Class<T> targetClass, E source) {
        if (null == source) {
            return null;
        }
        T target = null;
        try {
            target = targetClass.newInstance();
        } catch (InstantiationException e) {
            logger.warn("创建目标类对象出错,InstantiationException:{}", e.getMessage());
        } catch (IllegalAccessException e) {
            logger.warn("创建目标类对象出错,IllegalAccessException:{}", e.getMessage());
        }
        Field[] targetFields = target.getClass().getDeclaredFields();
        Field s;
        for (Field t : targetFields) {
            try {
                s = source.getClass().getDeclaredField(t.getName());
                t.setAccessible(true);
                s.setAccessible(true);
                t.set(target, s.get(source));
            } catch (IllegalAccessException e) {
                logger.warn("属性拾取器出错,IllegalAccessException:{}", e.getMessage());
            } catch (NoSuchFieldException e) {
                logger.warn("属性拾取器出错,NoSuchFieldException:{}", e.getMessage());
            }
        }
        return target;
    }

    /**
     * 属性拾取到MAP
     *
     * @param source
     * @param properties
     * @param <T>
     * @return
     */
    public static <T> Map pick(T source, String[] properties) {
        if (null == source) {
            return null;
        }
        Map<String, Object> map = new HashMap();
        Field s;
        for (String property : properties) {
            try {
                s = source.getClass().getDeclaredField(property);
                s.setAccessible(true);
                map.put(property, s.get(source));
            } catch (IllegalAccessException e) {
                logger.warn("属性拾取器出错,IllegalAccessException:{}", e.getMessage());
            } catch (NoSuchFieldException e) {
                logger.warn("属性拾取器出错,NoSuchFieldException:{}", e.getMessage());
            }
        }
        return map;
    }

    /**
     * 属性拾取到Map,以List返回
     *
     * @param sources
     * @param properties
     * @param <T>
     * @return
     */
    public static <T> List pick(List<T> sources, String[] properties) {
        if (null == sources) {
            return null;
        }
        List<Map> list = new ArrayList<>();
        if (sources.size() == 0) {
            return list;
        }
        for (T obj : sources) {
            list.add(pick(obj, properties));
        }
        return list;
    }

    /**
     * 排除属性后拾取到MAP
     *
     * @param source
     * @param excludes
     * @param <T>
     * @return
     */
    public static <T> Map pickExclude(T source, String[] excludes) {
        if (null == source) {
            return null;
        }
        Map<String, Object> map = new HashMap();
        Field[] sourceFields = source.getClass().getDeclaredFields();
        for (Field field : sourceFields) {
            try {
                if (!ArrayUtils.contains(excludes, field.getName())) {
                    field.setAccessible(true);
                    map.put(field.getName(), field.get(source));
                }
            } catch (IllegalAccessException e) {
                logger.warn("属性拾取器出错,IllegalAccessException:{}", e.getMessage());
            }
        }
        return map;
    }

    public static <T> Map pickExclude(T source) {
        String[] excludes = new String[]{"createBy", "updateTime", "updateBy"};
        return pickExclude(source, excludes);
    }

    /**
     * 排除属性后拾取到Map,以List返回
     *
     * @param sources
     * @param excludes
     * @param <T>
     * @return
     */
    public static <T> List<Map> pickExclude(List<T> sources, String[] excludes) {
        if (null == sources) {
            return null;
        }
        List<Map> list = new ArrayList<>();
        if (sources.size() == 0) {
            return list;
        }
        for (T obj : sources) {
            list.add(pickExclude(obj, excludes));
        }
        return list;
    }

    public static <T> List<Map> pickExclude(List<T> sources) {
        String[] excludes = new String[]{"createBy", "updateTime", "updateBy"};
        return pickExclude(sources, excludes);
    }

}
